package com.alibaba.polardbx.optimizer.config.table.collation;

import com.alibaba.polardbx.common.charset.CollationName;
import com.alibaba.polardbx.common.charset.SortKey;
import com.alibaba.polardbx.optimizer.config.table.charset.CharsetFactory;
import com.alibaba.polardbx.optimizer.config.table.charset.CharsetHandler;
import io.airlift.slice.Slices;
import org.junit.Assert;
import org.junit.Test;

// MySQL8.0 unit test: unittest/gunit/strings_strnxfrm-t.cc:1796
public class Utf8mb4Zh0900AsCsSortKeyTest {

    @Test
    public void test0() {
        CollationHandler collationHandler =
            CharsetFactory.INSTANCE.createCollationHandler(CollationName.UTF8MB4_ZH_0900_AS_CS);

        CharsetHandler charsetHandler = collationHandler.getCharsetHandler();

        byte[] src = new byte[] {
            /* Non-Han characters that have implicit weight. */
            (byte) 0xF0, (byte) 0x97, (byte) 0x86, (byte) 0xA0, (byte) 0xF0, (byte) 0xAC, (byte) 0xBA, (byte) 0xA2,
            (byte) 0xF0, (byte) 0xAE, (byte) 0xAF, (byte) 0xA0, (byte) 0xF0, (byte) 0xB3, (byte) 0x8C, (byte) 0xB3
        };

        int maxLen = 72;
        SortKey sortKey = collationHandler.getSortKey(
            Slices.wrappedBuffer(src), maxLen
        );
        byte[] result = sortKey.keys;

        print(result, maxLen);

    }

    @Test
    public void test1() {
        CollationHandler collationHandler =
            CharsetFactory.INSTANCE.createCollationHandler(CollationName.UTF8MB4_ZH_0900_AS_CS);

        CharsetHandler charsetHandler = collationHandler.getCharsetHandler();

//            String src =
//                "\u00E9\u963F\u00E5\u0092\u008F" +  // The first and last Han character in zh.xml
//                    "\uD869\uDEA1" +                   // The last Han character (encoded as a surrogate pair)
//                    "\u0101\u0061\u0062\u012B\u0075\u0055\u0146\u005A" +  // Some latin characters
//                    // are used as Bopomofo.
//                    "\uD805\uDD86" +                   // The last character that has explicit weight
//                    // in the DUCET.
//                    /* Non-Han characters that have implicit weight. */
//                    "\uD806\uDDA0\uD82C\uDCA2\uD82E\uDDA0\uD82F\u8CB3";
//
//        System.out.println(src);

        byte[] src = new byte[] {
            (byte) 0xE9, (byte) 0x98, (byte) 0xBF, (byte) 0xE5, (byte) 0x92, (byte) 0x97,
            // The first and last Han character in zh.xml
            (byte) 0xF0, (byte) 0xAC, (byte) 0xBA, (byte) 0xA1,          // The last Han character
            (byte) 0xC4, (byte) 0x81, (byte) 0x61, (byte) 0x62, (byte) 0xC5, (byte) 0xAB, (byte) 0x75, (byte) 0x55,
            (byte) 0xC7, (byte) 0x96, (byte) 0x5A,  // Some latin characters
            // are used as Bopomofo.
            (byte) 0xF0, (byte) 0x94, (byte) 0x99, (byte) 0x86,  // The last character that has explicit weight
            // in the DUCET.

            /* Non-Han characters that have implicit weight. */
            (byte) 0xF0, (byte) 0x97, (byte) 0x86, (byte) 0xA0, (byte) 0xF0, (byte) 0xAC, (byte) 0xBA, (byte) 0xA2,
            (byte) 0xF0, (byte) 0xAE, (byte) 0xAF, (byte) 0xA0, (byte) 0xF0, (byte) 0xB3, (byte) 0x8C, (byte) 0xB3
        };

        System.out.println(new String(src));

        byte[] full_answer_with_pad = new byte[] {
            // level 1
            (byte) 0x1C, (byte) 0x47, (byte) 0xBD, (byte) 0xBE,
            // The first and last Han character in zh.xml
            (byte) 0xBD, (byte) 0xC3, (byte) 0xCE, (byte) 0xA1,  // The last Han character
            /* Latin characters. Some are used as Bopomofo. */
            (byte) 0xBD, (byte) 0xC4, (byte) 0xBD, (byte) 0xC4, (byte) 0xBD, (byte) 0xDD, (byte) 0xC0, (byte) 0x32,
            (byte) 0xC0, (byte) 0x32, (byte) 0xC0, (byte) 0x32,
            (byte) 0xC0, (byte) 0x32, (byte) 0xC0, (byte) 0x9E,

            (byte) 0xF6, (byte) 0x20,  // The last character that has explicit weight in the DUCET.
            /* Non-Han characters that have implicit weight. */
            (byte) 0xF6, (byte) 0x21, (byte) 0x81, (byte) 0xA0, (byte) 0xF6, (byte) 0x27, (byte) 0xCE, (byte) 0xA2,
            (byte) 0xF6, (byte) 0x27, (byte) 0xEB, (byte) 0xE0,
            (byte) 0xF6, (byte) 0x28, (byte) 0xB3, (byte) 0x33,

            // level separator.
            0x00, 0x00,

            // level 2
            0x00, 0x20, 0x00, 0x20,  // The first and last Han character in zh.xml
            0x00, 0x20,              // The last Han character

            /* Latin characters. Some are used as Bopomofo. */
            0x00, 0x1F, 0x01, 0x16, 0x00, 0x20, 0x00, 0x20, 0x00, 0x1F, 0x01, 0x16,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x01, 0x16, 0x00, 0x20,

            0x00, 0x20,  // The last character that has explicit weight in the DUCET.
            /* Non-Han characters that have implicit weight. */
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            // level separator.
            0x00, 0x00,

            // level 3
            0x00, 0x02, 0x00, 0x02,  // The first and last Han character in zh.xml
            0x00, 0x02,              // The last Han character
            /* Latin characters. Some are used as Bopomofo. */
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x08,
            0x00, 0x08, 0x00, 0x08,

            0x00, 0x02,  // The last character that has explicit weight in the DUCET.
            /* Non-Han characters that have implicit weight. */
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02};

        int full_answer_with_pad_size = full_answer_with_pad.length;

        for (int maxLen = 0; maxLen < full_answer_with_pad_size; maxLen += 2) {
            SortKey sortKey = collationHandler.getSortKey(
                Slices.wrappedBuffer(src), maxLen
            );

            byte[] result = sortKey.keys;

            try {
                Assert.assertTrue(equals(full_answer_with_pad, result, maxLen));

                System.out.println("success: ");
                print(result, maxLen);
                System.out.println();

            } catch (AssertionError e) {
                System.out.println("max len:");
                System.out.println(maxLen);
                System.out.println("source data:");
                print(src, Math.min(maxLen, src.length));
                System.out.println("expected: ");
                print(full_answer_with_pad, maxLen);
                System.out.println("but was: ");
                print(result, maxLen);
                // throw e;
            }

        }
    }

    @Test
    public void test2() {
        CollationHandler collationHandler =
            CharsetFactory.INSTANCE.createCollationHandler(CollationName.UTF8MB4_ZH_0900_AS_CS);

        CharsetHandler charsetHandler = collationHandler.getCharsetHandler();

        byte[] content = ("春江潮水连海平，海上明月共潮生。" +
            "滟滟随波千万里，何处春江无月明！" +
            "江流宛转绕芳甸，月照花林皆似霰；" +
            "空里流霜不觉飞，汀上白沙看不见。" +
            "江天一色无纤尘，皎皎空中孤月轮。" +
            "江畔何人初见月？江月何年初照人？" +
            "人生代代无穷已，江月年年只相似。" +
            "不知江月待何人，但见长江送流水。" +
            "白云一片去悠悠，青枫浦上不胜愁。" +
            "谁家今夜扁舟子？何处相思明月楼？").getBytes();
        int len = content.length;

        int[] expected = new int[] {
            0x2C, 0xD0, 0x4F, 0xF1, 0x28, 0x08, 0x87, 0xE8, 0x60, 0x4C, 0x42, 0xEF,
            0x75, 0x93, 0x02, 0x22, 0x42, 0xEF, 0x83, 0x8A, 0x6C, 0x4F, 0xAF, 0x96,
            0x3F, 0x58, 0x28, 0x08, 0x84, 0xCF, 0x02, 0x8A, 0xA3, 0xA4, 0xA3, 0xA4,
            0x8A, 0x5F, 0x23, 0x71, 0x78, 0xA8, 0x93, 0x1A, 0x5E, 0xD9, 0x02, 0x22,
            0x44, 0xAC, 0x2B, 0xD5, 0x2C, 0xD0, 0x4F, 0xF1, 0x96, 0x31, 0xAF, 0x96,
            0x6C, 0x4F, 0x02, 0x60, 0x4F, 0xF1, 0x63, 0x7B, 0x92, 0xDD, 0xBA, 0x2E,
            0x7F, 0x07, 0x39, 0x15, 0x32, 0xB2, 0x02, 0x22, 0xAF, 0x96, 0xB4, 0x41,
            0x47, 0xD7, 0x62, 0x27, 0x51, 0x4C, 0x85, 0xE9, 0x81, 0x86, 0x02, 0x34,
            0x59, 0x09, 0x5E, 0xD9, 0x63, 0x7B, 0x87, 0xBA, 0x24, 0x78, 0x56, 0x5A,
            0x39, 0x48, 0x02, 0x22, 0x8F, 0x74, 0x83, 0x8A, 0x1E, 0x4D, 0x82, 0x46,
            0x57, 0xD9, 0x24, 0x78, 0x4F, 0x79, 0x02, 0x8A, 0x4F, 0xF1, 0x8E, 0x8A,
            0xA6, 0x3E, 0x81, 0xEE, 0x96, 0x31, 0x99, 0x9E, 0x28, 0x97, 0x02, 0x22,
            0x50, 0xC2, 0x50, 0xC2, 0x59, 0x09, 0xB8, 0x20, 0x3F, 0xCC, 0xAF, 0x96,
            0x66, 0xC9, 0x02, 0x8A, 0x4F, 0xF1, 0x72, 0xB6, 0x44, 0xAC, 0x7F, 0x11,
            0x2B, 0x7B, 0x4F, 0x79, 0xAF, 0x96, 0x02, 0x66, 0x4F, 0xF1, 0xAF, 0x96,
            0x44, 0xAC, 0x6F, 0xD5, 0x2B, 0x7B, 0xB4, 0x41, 0x7F, 0x11, 0x02, 0x66,
            0x7F, 0x11, 0x84, 0xCF, 0x2F, 0xE2, 0x2F, 0xE2, 0x96, 0x31, 0x7B, 0xE1,
            0xA7, 0x41, 0x02, 0x22, 0x4F, 0xF1, 0xAF, 0x96, 0x6F, 0xD5, 0x6F, 0xD5,
            0xB6, 0xC3, 0x9B, 0x15, 0x85, 0xE9, 0x02, 0x8A, 0x24, 0x78, 0xB6, 0x2E,
            0x4F, 0xF1, 0xAF, 0x96, 0x2F, 0xF4, 0x44, 0xAC, 0x7F, 0x11, 0x02, 0x22,
            0x30, 0x86, 0x4F, 0x79, 0xB3, 0xDD, 0x4F, 0xF1, 0x89, 0x2A, 0x63, 0x7B,
            0x87, 0xE8, 0x02, 0x8A, 0x1E, 0x4D, 0xB0, 0x1B, 0xA6, 0x3E, 0x75, 0x00,
            0x7D, 0x93, 0xAB, 0xAF, 0xAB, 0xAF, 0x02, 0x22, 0x7B, 0x7D, 0x3A, 0x63,
            0x76, 0xA2, 0x83, 0x8A, 0x24, 0x78, 0x85, 0x16, 0x2B, 0x2D, 0x02, 0x8A,
            0x84, 0x30, 0x4D, 0xF3, 0x52, 0x63, 0xA5, 0xC7, 0x21, 0xE0, 0xB8, 0x87,
            0xBC, 0x16, 0x02, 0x66, 0x44, 0xAC, 0x2B, 0xD5, 0x9B, 0x15, 0x88, 0x52,
            0x6C, 0x4F, 0xAF, 0x96, 0x64, 0xA1, 0x02, 0x66, 0x00, 0x00, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x20,
            0x00, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x03, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x03,
            0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0x02,
            0x00, 0x02, 0x00, 0x03};

        SortKey sortKey = collationHandler.getSortKey(Slices.wrappedBuffer(content), expected.length);
        byte[] results = sortKey.keys;

        try {
            Assert.assertTrue(equals(results, expected, results.length));

            System.out.println("success: ");
            print(results, results.length);
            System.out.println();

        } catch (AssertionError e) {
            System.out.println("fail: ");
            print(results, results.length);
        }
    }

    private static boolean equals(byte[] bytes1, byte[] bytes2, int len) {
        for (int i = 0; i < len; i++) {
            if (bytes1[i] != bytes2[i]) {
                return false;
            }
        }
        return true;
    }

    private static boolean equals(byte[] bytes1, int[] intArray, int len) {
        for (int i = 0; i < len; i++) {
            if (Byte.toUnsignedInt(bytes1[i]) != intArray[i]) {
                return false;
            }
        }
        return true;
    }

    private static void print(byte[] result, int len) {
        final int lineLength = 12;

        for (int i = 0; i < len; i++) {
            String hexString = String.format("0x%02X", result[i]);

            System.out.print(hexString);

            if (i < len - 1) {
                System.out.print(", ");
            }

            if ((i + 1) % lineLength == 0 || i == len - 1) {
                System.out.println();
            }
        }
    }

}
